package com.shiroha.video.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.shiroha.common.exception.BadRequestException;
import com.shiroha.common.exception.InternalServiceException;
import com.shiroha.common.utils.FileUtils;
import com.shiroha.video.mapper.WorkImageMapper;
import com.shiroha.video.pojo.WorkImage;
import com.shiroha.video.pojo.dto.WorkImageDTO;
import com.shiroha.video.pojo.dto.WorkMetaData;
import com.shiroha.video.pojo.vo.ImageInfo;
import com.shiroha.video.pojo.vo.ImageResponse;
import com.shiroha.video.service.IWorkImageService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;

import static com.shiroha.video.pojo.table.Tables.WORK_IMAGE;

@Service
@Slf4j
public class WorkImageServiceImpl extends ServiceImpl<WorkImageMapper, WorkImage> implements IWorkImageService {

    /**
     * 作品图片上传顶级目录
     */
    private static final String WORK_IMAGE_UPLOAD_DIR = "deploy/upload/works/";

    /**
     * 上传作品图集
     *
     * @param workMetaData 作品元数据
     * @return 执行成功返回封面路径，执行失败则返回空
     */
    @Override
    public Optional<String> saveWorkImages(WorkMetaData workMetaData) {
        try {
            List<WorkImageDTO> workImageDTOS = uploadImagesToFileSystem(workMetaData.getWorkImageDTOList());
            List<WorkImage> workImages = workImageDTOS.stream().map(this::toWorkImage).toList();
            return this.saveBatch(workImages) ? Optional.of(workImageDTOS.getFirst().getImagePath()) : Optional.empty();
        } catch (Exception e) {
            log.error("保存图片失败", e);
            throw new InternalServiceException("保存图片失败");
        }
    }

    /**
     * 获取图集作品的图片列表
     *
     * @param workId 作品ID
     * @return 含图片信息的封装响应体
     */
    @Override
    public ImageResponse getWorkImages(Long workId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(WORK_IMAGE.WORK_ID.eq(workId));
        List<WorkImage> workImages = this.list(queryWrapper);
        return new ImageResponse(workImages.stream().map(this::toImageInfo).toList());
    }

    /**
     * 获取作品图集的二进制数据
     *
     * @param workId 作品ID
     * @param index  图片序号
     * @return 字节数组
     */
    @Override
    public byte[] getWorkImageBytes(Long workId, int index) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(WORK_IMAGE.WORK_ID.eq(workId))
                .and(WORK_IMAGE.SEQUENCE.eq(index));
        WorkImage workImage = this.getOne(queryWrapper);
        if(workImage == null) throw new BadRequestException("序号超出范围");
        String imagePath = workImage.getImagePath();
        try {
            return Files.readAllBytes(Paths.get(imagePath));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new InternalServiceException("文件读取异常");
        }
    }

    /**
     * 上传图片到本地并获取相对路径。
     * 保存的目录结构如下：
     * <pre>
     * /deploy/
     * ├── upload/
     * │   ├── works/
     * │   │   ├── {workId}/
     * │   │   │   ├── images/
     * │   │   │   │   ├── {uniqueFileName}.jpg/png
     * </pre>
     * @param workImageDTOS DTO对象列表
     * @return 经过处理后的DTO对象列表
     * @throws Exception 异步执行失败时抛出异常
     */
    public List<WorkImageDTO> uploadImagesToFileSystem(@NonNull List<WorkImageDTO> workImageDTOS) throws Exception {
        // 提取第一张图片并设置为封面
        WorkImageDTO first = workImageDTOS.getFirst();
        first.setCover(true);

        Long workId = first.getWorkId();

        // 收集file到列表中
        List<MultipartFile> files = workImageDTOS.stream().map(WorkImageDTO::getFile).toList();
        List<String> imagePaths = FileUtils.uploadFilesAsync(files, getWorkImageUploadDir(workId), true).get();

        // 将文件路径赋值给 workImageDTOS 中的元素
        for (int i = 0; i < workImageDTOS.size(); i++) {
            workImageDTOS.get(i).setImagePath(getWorkImageUploadDir(workId) + imagePaths.get(i));
            workImageDTOS.get(i).setSequence(i + 1);
        }

        return workImageDTOS;
    }

    // 生成上传目录路径
    private String getWorkImageUploadDir(Long workId) {
        return WORK_IMAGE_UPLOAD_DIR + workId + "/images/";
    }

    private WorkImage toWorkImage(WorkImageDTO workImageDTO) {
        WorkImage workImage = new WorkImage();
        workImage.setWorkId(workImageDTO.getWorkId());
        workImage.setSequence(workImageDTO.getSequence());
        workImage.setImagePath(workImageDTO.getImagePath());
        workImage.setCover(workImageDTO.isCover());
        return workImage;
    }

    private ImageInfo toImageInfo(WorkImage workImage) {
        ImageInfo imageInfo = new ImageInfo();
        imageInfo.setIndex(workImage.getSequence());
        imageInfo.setCover(workImage.isCover());
        imageInfo.setUrl(getImageUrl(workImage.getWorkId(), workImage.getSequence()));
        imageInfo.setDescription(workImage.getDescription());
        return imageInfo;
    }

    private String getImageUrl(Long workId, int index) {
        return "/vs/works/" + workId + "/images/" + index;
    }
}
